#version 430 core

#define BLOCK_SIZE 512
#define HALF_BLOCK_SIZE 256

layout(local_size_x=HALF_BLOCK_SIZE) in;

layout(binding=2) coherent buffer inVectorBuffer
{
	float inVector[];
};

layout(binding=3) coherent buffer outVectorBuffer
{
	float outVector[];
};

uniform uint n;
uniform uint outIndex[3]; // outVector[outIndex[0]] = sol; outVector[outIndex[1]] = sol/outVector[extraTermIndex]; outVector[outIndex[2]] = outVector[extraTermIndex]/sol;
uniform uint extraTermIndex;

shared float sData[BLOCK_SIZE];

void main(void)
{
	uint lid = gl_LocalInvocationID.x;

	sData[lid] = 0;
	//sData[lid+BLOCK_SIZE/2] = 0;
	if (lid < n)
		sData[lid] = inVector[lid];
	if (lid+BLOCK_SIZE/2 < n)
		sData[lid] += inVector[lid+BLOCK_SIZE/2];

	memoryBarrierShared();
	barrier();

#if (BLOCK_SIZE >= 256)
	if (lid < 128)
	{
		sData[lid] += sData[lid+128];
		memoryBarrierShared();
		barrier();
	}
#endif

#if (BLOCK_SIZE >= 128)
	if (lid < 64)
	{
		sData[lid] += sData[lid+64];
		memoryBarrierShared();
		barrier();
	}
#endif

	if (lid < 32)
	{
#if (BLOCK_SIZE >= 64)
		sData[lid] += sData[lid+32];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 32)
		sData[lid] += sData[lid+16];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 16)
		sData[lid] += sData[lid+8];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 8)
		sData[lid] += sData[lid+4];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 4)
		sData[lid] += sData[lid+2];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 2)
		sData[lid] += sData[lid+1];
#endif
	}

	if (lid == 0)
	{
		float sol = sData[0];
		float extraTerm = outVector[extraTermIndex];
		outVector[outIndex[0]] = sol;
		outVector[outIndex[1]] = mix(sol / extraTerm, 0.0f, abs(extraTerm) < 0.0001);
		outVector[outIndex[2]] = mix(extraTerm / sol, 0.0f, abs(sol) < 0.0001);
	}
}